﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml;
using System.Security.Cryptography;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.FAS.Runtime.Base.Entity;

namespace T.FAS.Runtime.DataModel.Dao
{
    /// <summary>
    /// 扩展类
    /// </summary>
    public static class Addons
    {
        private static Dictionary<Type, Func<object, string>> s_convertFunc = new Dictionary<Type, Func<object, string>> {
            { typeof(bool), o => o.ToString().ToLower() },
        };

        public static string Format(this string str, Dictionary<string,object> dict)
        {
            if (str == null || dict == null || dict.Keys.Count == 0)
                return str;
            try
            {
                foreach (var key in dict.Keys)
                {
                    string pattern = $"{{{key}}}";
                    string value = ConvertString(dict[key]);

                    str = Regex.Replace(str, pattern, value);
                }
                return str;
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.Tool.Error, e.Message, e);
            }
        }

        public static string Format(this string str, object entity, short mode=0)
        {
            if (str == null || entity == null)
                return str;
            Type t = entity.GetType();
            var attrs = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            var fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance);
            Regex regex = new Regex($"({{[a-zA-Z0-9_]+}})");
            MatchCollection group = regex.Matches(str);
            HashSet<string> existattrs = new HashSet<string>();
            HashSet<string> existfields = new HashSet<string>();
            HashSet<string> notexistkeywords = new HashSet<string>();

            try
            {
                foreach (Match item in group)
                {
                    if (item.Success)
                    {
                        var keyword = item.Value.Trim('{').Trim('}');
                        if (attrs.Where(attr => string.Equals(attr.Name, keyword)).Count() == 1)
                        {
                            existattrs.Add(keyword);
                        }
                        else if (fields.Where(attr => string.Equals(attr.Name, keyword)).Count() == 1)
                        {
                            existfields.Add(keyword);
                        }
                        else
                        {
                            notexistkeywords.Add(keyword);
                        }
                    }
                }
                if (notexistkeywords.Count > 0)
                {
                    var msg = $"实体类{t.Name}中不包含{string.Join(",", notexistkeywords.ToArray())}字段";
                    if (mode == 0)
                        Console.WriteLine(msg);
                    else
                        throw new FasException(DataModelErrorCode.Tool.Error, msg);
                }
                foreach (var key in existattrs)
                {
                    string pattern = $"{{{key}}}";
                    var value = ConvertString(attrs.Where(attr => attr.Name == key).FirstOrDefault().GetValue(entity));
                    str = Regex.Replace(str, pattern, value);
                }
                foreach (var key in existfields)
                {
                    string pattern = $"{{{key}}}";
                    var value = ConvertString(fields.Where(attr => attr.Name == key).FirstOrDefault().GetValue(entity));
                    str = Regex.Replace(str, pattern, value);
                }
                return str;

            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.Tool.Error, "string Format工具类异常", e);
            }
        }

        public static string Format(this string str, params object[] datas)
        {
            foreach (var data in datas)
            {
                if(data is Dictionary<string, object> dict)
                {
                    str = str.Format(dict);
                }
                else
                {
                    str = str.Format(data);
                }
            }
            return str;
        }

        public static string ConvertString(object obj)
        {
            if (obj == null)
                return "";
            var type = obj.GetType();
            string value = string.Empty;
            if (s_convertFunc.Keys.Contains(type))
                value = s_convertFunc[type](obj);
            else
                value = obj.ToString();
            return value;
        }

        public static string GetMD5Hash(this string str)
        {
            byte[] hash;
            string result= string.Empty;
            using (MD5 md5 = MD5.Create())
            {
                hash = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
            }
            for (int i = 0; i < hash.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符
                result = result + hash[i].ToString("x2");
            }
            return result;
        }
    }

    /// <summary>
    /// XML helper
    /// </summary>
    public class XMLHelper
    {
        public string Path { get; set; }
        public XmlDocument XmlDoc { get; set; }
        public XMLHelper(string xmlContent)
        {
            try
            {
                if (XmlDoc == null)
                    XmlDoc = new XmlDocument();
                XmlDoc.LoadXml(xmlContent);
            }
            catch (Exception e)
            {

                throw new FasException(DataModelErrorCode.Tool.Error, "加载xml失败", e);
            }
        }

        /// <summary>
        /// 获取节点内内容
        /// </summary>
        /// <param name="selector"></param>
        /// <returns></returns>
        public string GetSingleNodeContent(string selector)
        {
            return XmlDoc.SelectSingleNode(selector)?.InnerText;
        }
    }

    public class CommonTools
    {

    }
}
